package com.gton.person.controller;

import com.gton.person.commons.ResultAdvice;
import com.gton.person.commons.captcha.CaptchaRepository;
import com.gton.person.entity.Student;
import com.gton.person.service.RoleService;
import com.gton.person.service.StudentService;
import com.wf.captcha.SpecCaptcha;
import com.wf.captcha.base.Captcha;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.time.LocalDateTime;


/**
 * @program: boot-easyui
 * @description: 登录功能与注册功能
 * @author: GuoTong
 * @create: 2020-11-05 13:55
 **/
//RestController   返回字符串（默认），当设置了modelandview时，可以定制与页面和数据切换
/**主要是控制反转--处理器控制器||处理器适配器：里面每一个处理请求的方法是处理器*/
@RestController
@Slf4j
public class LoginController {

    /**
     * 注入依赖：这里的这个是redis的模板依赖，方便我们java对于redis操作
     */
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 加密依赖
     */
    @Autowired
    private PasswordEncoder bCryptPasswordEncoder;

    /**
     * 真正的用户类的service
     */
    @Autowired
    private StudentService studentService;

    /**
     * 里面封装了redis的相关操作，和权限相关的业务处理
     */
    @Resource
    private RoleService roleService;

    /**
     * 验证码的图片容器
     */
    @Autowired
    private CaptchaRepository<HttpServletRequest> captchaRepository;


    /**
     * 该方法是注册用户的方法，默认放开访问控制
     * 登录表用户注册
     *
     * @param userName,verCode,password
     */
    @PostMapping("/register")
    @ApiOperation(value = "注册", notes = "密码加密，验证入库")
    public ResultAdvice signUp(@RequestParam(value = "username") String userName
            , @RequestParam(value = "verCode", required = true) String verCode
            , @RequestParam(value = "password") String password) {
        //验证码判断：verCode
        String captcha = redisTemplate.opsForValue().get("captcha");
        if (!captcha.equalsIgnoreCase(verCode)) {
            System.out.println(verCode + ":::" + captcha);
            return ResultAdvice.error("验证码不正确");
        }
        Student student = new Student();
        student.setUsername(userName);
        student.setPassword(password);
        //明文密码，保存至明文字段
        student.setPwdShow(student.getPassword());
        //判断传入的参数是否有效
        String errorAdvice = studentService.getResultAdvice(student);
        //如果校验失败就返回错误信息
        if (errorAdvice != null) {
            return ResultAdvice.error(errorAdvice);
        }

        //原始密码字段需要加盐加密
        student.setPassword(bCryptPasswordEncoder.encode(student.getPassword()));
        //保存用户
        System.out.println(student);
        try {
            //执行保存操作,用户表保存，然后需要初始化赋予一定的权限
            boolean registerIsOk = studentService.registerUser(student);
            return registerIsOk ? ResultAdvice.OK() : ResultAdvice.error("注册失败");
        } catch (Exception e) {
            log.error("LoginController->----signUp()出现异常");
            return ResultAdvice.error("注册时出现意外");
        }
    }


    @RequestMapping("/login/error")
    @ApiOperation(value = "登陆失败", notes = "失败登陆")
    public ModelAndView loginError() {
        ModelAndView modelAndView = new ModelAndView("/views/login");
        modelAndView.addObject("msg", "账户或者密码错误");
        return modelAndView;
    }

    //处理器：具体处理某一个请求的业务逻辑的方法
    @RequestMapping("/login")
    public ModelAndView login() {
        //跳转页面：可以使用modelandview对象，
        // 它是模型视图解析器：可以自定义配置，我们这里使用的是thymeleaf模板引擎：默认方式：在配置文件可以配置
        ModelAndView mv = new ModelAndView();
        //请求与响应中的数据交互：服务端---响应给请求者的信息。。。
        //请求者发送给服务端的数据由方法（处理器）处理，接收请求者的数据
        mv.addObject("域对象：key", "域对象：值（object）");
        //设置响应返回的页面
        mv.setViewName("您需要跳转的页面");
        return mv;
    }


    //第三方优雅的验证码：可以查看官方帮助文档自己div
    @RequestMapping("/captcha")
    @ApiOperation(value = "验证码", notes = "登录时候必须输入验证码：60秒有效！！")
    //springmvc默认支持原始的请求与响应的对象，你直接卸载方法形参中，处理器控制器||会自动在我们这个处理器中注入您需要的内置对象
    public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 设置请求头为输出图片类型
        response.setContentType("image/gif");
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);

        // 三个参数分别为宽、高、位数
        SpecCaptcha specCaptcha = new SpecCaptcha(130, 35, 5);
        // 设置字体// 有默认字体，可以不用设置
        specCaptcha.setFont(new Font("Verdana", Font.PLAIN, 32));
        // 设置类型，纯数字、纯字母、字母数字混合
        specCaptcha.setCharType(Captcha.TYPE_DEFAULT);

        // 验证码存入session
        //request.getSession().setAttribute("captcha", specCaptcha.text().toLowerCase());
        //获取验证码：并且把验证码：存入redis
        String yzm = specCaptcha.text().toLowerCase();
        log.info(LocalDateTime.now() + ":->当前验证码：" + yzm);
        /*保存验证码：到Redis里面*/
        captchaRepository.save(request, yzm);
        // 输出图片流
        specCaptcha.out(response.getOutputStream());
    }
}
